package lock;

/**
 * ReentrantLock(重入锁)
 * 中断响应（lockInterruptibly）
 * 对于 synchronized 来说，如果一个线程在等待锁，那么结果只有两种情况，获得这把锁继续执行，或者线程就保持等待。
 * 而使用重入锁，提供了另一种可能，这就是线程可以被中断。也就是在等待锁的过程中，程序可以根据需要取消对锁的需求。
 * <p>
 * 本例子中，产生了死锁，但得益于锁中断，最终解决了这个死锁
 */

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo2 implements Runnable {
    //声明一把锁，其中ReentrantLock（可重入的互斥锁）是Lock接口的一个实现
    public static ReentrantLock lock1 = new ReentrantLock();
    public static ReentrantLock lock2 = new ReentrantLock();
    int index = 0;

    public ReentrantLockDemo2(int index) {
        this.index = index;
    }

    @Override
    public void run() {
        try {
            if (index == 1) {
                /*
                1）lock(), 拿不到lock就不罢休，不然线程就一直block。 比较无赖的做法。
                2）tryLock()，马上返回，拿到lock就返回true，不然返回false。 比较潇洒的做法。    
                            带时间限制的tryLock()，拿不到lock，就等一段时间，超时返回false。比较聪明的做法。
                3）lockInterruptibly()就稍微难理解一些。但优先响应中断。
                 */

                lock1.lockInterruptibly();//如果当前线程未被中断，则获取锁。获得锁，但优先响应中断。
                Thread.sleep(500);
                lock2.lockInterruptibly();
                System.out.println(Thread.currentThread().getName() + "，执行完毕！");
            } else {
                lock2.lockInterruptibly();
                Thread.sleep(500);
                lock1.lockInterruptibly();
                System.out.println(Thread.currentThread().getName() + "，执行完毕！");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //查询当前线程是否保持此锁
            if (lock1.isHeldByCurrentThread()) {
                lock1.unlock();
                System.out.println(Thread.currentThread().getName() + "，lock1解锁。");
            }
            if (lock2.isHeldByCurrentThread()) {
                lock2.unlock();
                System.out.println(Thread.currentThread().getName() + "，lock2解锁。");
            }
            System.out.println(Thread.currentThread().getName() + "，退出。");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ReentrantLockDemo2 intLock1 = new ReentrantLockDemo2(1);
        ReentrantLockDemo2 intLock2 = new ReentrantLockDemo2(2);
        Thread thread1 = new Thread(intLock1, "线程1");
        Thread thread2 = new Thread(intLock2, "线程2");
        thread1.start();
        thread2.start();
        Thread.sleep(2000);//main 线程处于休眠（sleep）状态，两线程此时处于死锁的状态
        thread2.interrupt(); // ?? 中断线程2, thread2 会放弃对 lock1 的申请，同时释放已获得的 lock2 ,这个操作导致 thread1 顺利获得 lock2，从而继续执行下去。
    }

}

/*
线程 thread1 和 thread2 启动后，thread1 先占用 lock1，再占用 lock2；thread2 反之，先占 lock2，后占 lock1。这便形成 thread1 和 thread2 之间的相互等待。

代码 60 行，main 线程处于休眠（sleep）状态，两线程此时处于死锁的状态，代码 61行 thread2 被中断（interrupt），故 thread2 会放弃对 lock1 的申请，同时释放已获得的 lock2。这个操作导致 thread1 顺利获得 lock2，从而继续执行下去。
 */